package main

import (
	"fmt"
	"os"
	"strings"
	"time"
)

// 抽象产品接口
type LogFormatter interface {
	Format(level string, message string, timestamp time.Time, fields map[string]interface{}) string
	GetFormatterType() string
}

type LogOutput interface {
	Write(formattedLog string) error
	Close() error
	GetOutputType() string
}

// 抽象工厂接口
type LoggingFactory interface {
	CreateFormatter(config map[string]interface{}) LogFormatter
	CreateOutput(config map[string]interface{}) LogOutput
	GetFactoryName() string
}

// 开发环境产品族
type DevelopmentFormatter struct {
	ColorEnabled bool
	ShowCaller   bool
}

func (d *DevelopmentFormatter) Format(level string, message string, timestamp time.Time, fields map[string]interface{}) string {
	var result strings.Builder

	if d.ColorEnabled {
		color := d.getColorCode(level)
		result.WriteString(fmt.Sprintf("\033[%sm", color))
	}

	result.WriteString(fmt.Sprintf("[%s] %s", level, timestamp.Format("15:04:05")))

	if d.ShowCaller {
		result.WriteString(" [caller]")
	}

	result.WriteString(fmt.Sprintf(" - %s", message))

	if len(fields) > 0 {
		var fieldStrs []string
		for k, v := range fields {
			fieldStrs = append(fieldStrs, fmt.Sprintf("%s=%v", k, v))
		}
		result.WriteString(fmt.Sprintf(" | %s", strings.Join(fieldStrs, ", ")))
	}

	if d.ColorEnabled {
		result.WriteString("\033[0m")
	}

	return result.String()
}

func (d *DevelopmentFormatter) getColorCode(level string) string {
	switch level {
	case "ERROR":
		return "31"
	case "WARN":
		return "33"
	case "INFO":
		return "32"
	default:
		return "37"
	}
}

func (d *DevelopmentFormatter) GetFormatterType() string {
	return "开发环境格式化器"
}

type DevelopmentOutput struct {
	ShowTimestamp bool
}

func (d *DevelopmentOutput) Write(formattedLog string) error {
	if d.ShowTimestamp {
		fmt.Printf("[%s] %s\n", time.Now().Format("15:04:05.000"), formattedLog)
	} else {
		fmt.Println(formattedLog)
	}
	return nil
}

func (d *DevelopmentOutput) Close() error {
	fmt.Println("开发环境输出器已关闭")
	return nil
}

func (d *DevelopmentOutput) GetOutputType() string {
	return "开发环境控制台输出"
}

// 生产环境产品族
type ProductionFormatter struct {
	IncludeHostname bool
	ServiceName     string
}

func (p *ProductionFormatter) Format(level string, message string, timestamp time.Time, fields map[string]interface{}) string {
	logData := map[string]interface{}{
		"level":     level,
		"message":   message,
		"timestamp": timestamp.Format(time.RFC3339),
		"service":   p.ServiceName,
	}

	if p.IncludeHostname {
		hostname, _ := os.Hostname()
		logData["hostname"] = hostname
	}

	for k, v := range fields {
		logData[k] = v
	}

	var parts []string
	for k, v := range logData {
		parts = append(parts, fmt.Sprintf(`"%s":"%v"`, k, v))
	}

	return fmt.Sprintf("{%s}", strings.Join(parts, ","))
}

func (p *ProductionFormatter) GetFormatterType() string {
	return "生产环境JSON格式化器"
}

type ProductionOutput struct {
	LogFile *os.File
	MaxSize int64
}

func (p *ProductionOutput) Write(formattedLog string) error {
	if p.LogFile == nil {
		return fmt.Errorf("日志文件未打开")
	}

	_, err := p.LogFile.WriteString(formattedLog + "\n")
	if err != nil {
		return err
	}

	stat, _ := p.LogFile.Stat()
	if stat.Size() > p.MaxSize {
		fmt.Println("日志文件达到最大大小，需要轮转")
	}

	return nil
}

func (p *ProductionOutput) Close() error {
	if p.LogFile != nil {
		fmt.Println("生产环境文件输出器已关闭")
		return p.LogFile.Close()
	}
	return nil
}

func (p *ProductionOutput) GetOutputType() string {
	return "生产环境文件输出"
}

// 具体工厂实现
type DevelopmentLoggingFactory struct{}

func (d *DevelopmentLoggingFactory) CreateFormatter(config map[string]interface{}) LogFormatter {
	colorEnabled := true
	showCaller := true

	if color, ok := config["color_enabled"].(bool); ok {
		colorEnabled = color
	}
	if caller, ok := config["show_caller"].(bool); ok {
		showCaller = caller
	}

	return &DevelopmentFormatter{
		ColorEnabled: colorEnabled,
		ShowCaller:   showCaller,
	}
}

func (d *DevelopmentLoggingFactory) CreateOutput(config map[string]interface{}) LogOutput {
	showTimestamp := true
	if ts, ok := config["show_timestamp"].(bool); ok {
		showTimestamp = ts
	}

	return &DevelopmentOutput{
		ShowTimestamp: showTimestamp,
	}
}

func (d *DevelopmentLoggingFactory) GetFactoryName() string {
	return "开发环境日志工厂"
}

type ProductionLoggingFactory struct{}

func (p *ProductionLoggingFactory) CreateFormatter(config map[string]interface{}) LogFormatter {
	serviceName := "unknown-service"
	includeHostname := true

	if name, ok := config["service_name"].(string); ok {
		serviceName = name
	}
	if hostname, ok := config["include_hostname"].(bool); ok {
		includeHostname = hostname
	}

	return &ProductionFormatter{
		IncludeHostname: includeHostname,
		ServiceName:     serviceName,
	}
}

func (p *ProductionLoggingFactory) CreateOutput(config map[string]interface{}) LogOutput {
	filename := "app.log"
	maxSize := int64(10 * 1024 * 1024)

	if name, ok := config["filename"].(string); ok {
		filename = name
	}
	if size, ok := config["max_size"].(int64); ok {
		maxSize = size
	}

	file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		fmt.Printf("无法打开日志文件: %v\n", err)
		return nil
	}

	return &ProductionOutput{
		LogFile: file,
		MaxSize: maxSize,
	}
}

func (p *ProductionLoggingFactory) GetFactoryName() string {
	return "生产环境日志工厂"
}

// 使用演示
func main() {
	fmt.Println("=== 日志系统工厂演示 ===")

	logFactories := map[string]LoggingFactory{
		"development": &DevelopmentLoggingFactory{},
		"production":  &ProductionLoggingFactory{},
	}

	for env, factory := range logFactories {
		fmt.Printf("=== %s ===\n", factory.GetFactoryName())

		// 创建格式化器
		formatterConfig := map[string]interface{}{
			"color_enabled":    true,
			"show_caller":      true,
			"service_name":     "test-service",
			"include_hostname": true,
		}
		formatter := factory.CreateFormatter(formatterConfig)

		// 创建输出器
		outputConfig := map[string]interface{}{
			"show_timestamp": true,
			"filename":       fmt.Sprintf("%s.log", env),
			"max_size":       int64(1024 * 1024),
		}
		output := factory.CreateOutput(outputConfig)

		if output != nil {
			fields := map[string]interface{}{
				"user_id": "12345",
				"action":  "login",
			}

			logMessage := formatter.Format("INFO", "用户登录成功", time.Now(), fields)
			output.Write(logMessage)
			output.Close()
		}
		fmt.Println()
	}
}
